package com.ryan.mdp.annotation.parser;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class MdpServiceConfig {

    private final Map<MethodCacheKey, MdpMethodConfig> mdpMethodConfigs = new HashMap<MethodCacheKey, MdpMethodConfig>();

    public void put(Method method, MdpMethodConfig methodConfig) {
        MethodCacheKey key = new MethodCacheKey(method);
        if (mdpMethodConfigs.containsKey(key)) {
            throw new IllegalArgumentException("Having duplicated method signture: " + method);
        } else {
            mdpMethodConfigs.put(key, methodConfig);
        }
    }

    public MdpMethodConfig get(Method method) {
        MethodCacheKey key = new MethodCacheKey(method);
        return mdpMethodConfigs.get(key);
    }

    /**
     * Simple wrapper class around a method name and its signature. Used as the
     * key when caching methods.
     */
    private static class MethodCacheKey {

        private final String name;

        private final Class<?>[] parameterTypes;

        /**
         * Create a new instance of <code>MethodCacheKey</code> with the
         * supplied method name and parameter list.
         * 
         * @param name
         *            the name of the method
         * @param parameterTypes
         *            the arguments in the method signature
         */
        public MethodCacheKey(Method method) {
            this.name = method.getName();
            this.parameterTypes = (method.getParameterTypes() != null ? method.getParameterTypes() : new Class[0]);
        }

        @Override
        public boolean equals(Object other) {
            if (other == null) {
                return false;
            }
            if (other == this) {
                return true;
            }
            MethodCacheKey otherKey = (MethodCacheKey) other;
            return (this.name.equals(otherKey.name) && Arrays.equals(this.parameterTypes, otherKey.parameterTypes));
        }

        @Override
        public int hashCode() {
            return this.name.hashCode();
        }
    }
}
